package com.example.myapplication.x.demo;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.FocusMeteringAction;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.VideoCapture;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.extensions.BeautyPreviewExtender;
import androidx.camera.extensions.HdrImageCaptureExtender;
import androidx.camera.extensions.NightImageCaptureExtender;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Rational;
import android.util.Size;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import com.example.myapplication.R;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.media.photocamera.utils.CameraFileUtils;
import com.media.photocamera.utils.CameraUiUtil;
import com.media.photocamera.view.CutMarkView;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@SuppressLint("RestrictedApi")
public class CameraXDemoActivity01 extends AppCompatActivity {
    private PreviewView previewView;
    private static final int REQUEST_CAMERA = 20,
            REQUEST_STORAGE = 30,
            REQUEST_STORAGE_VIDEO = 40;

    private static final String CAPTURED_FILE_NAME = "captured_picture";
    private static final String RECORDED_FILE_NAME = "recorded_video", RECORDED_FILE_NAME_END = "video/mp4";
    private Preview mPreview;


    private Camera mCamera;
    private ImageCapture mImageCapture;
    private ImageAnalysis mImageAnalysis;
    private VideoCapture mVideoCapture;

    private ProcessCameraProvider mCameraProvider;

    private boolean isBack = true, isAnalyzing, isVideoMode, isRecording, isCameraXHandling;
    private int recCount, picCount;

    private MultiFormatReader multiFormatReader = new MultiFormatReader();
    private TextView capture;
    private TextView video;
    private View qrCodeZone;
    private TextView qrCodeResult;
    private TextView night;
    private ImageView result;
    private CutMarkView markView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        WindowManager.LayoutParams lp = this.getWindow().getAttributes();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
        }
        this.getWindow().setAttributes(lp);
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_camerax_demo);
        getSupportActionBar().hide();
        previewView = findViewById(R.id.previewView);
        capture = findViewById(R.id.capture);
        video = findViewById(R.id.video);
        qrCodeZone = findViewById(R.id.qrCodeZone);
        qrCodeResult = findViewById(R.id.qrCodeResult);
        night = findViewById(R.id.night);
        result = findViewById(R.id.result);
        result.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                result.setVisibility(View.GONE);
            }
        });
        markView = findViewById(R.id.markView);
        previewView.post(new Runnable() {
            @Override
            public void run() {
                int width = previewView.getWidth();
                int height = previewView.getHeight();
                int screamWidth = (int) (width * 0.9);
                int targetHight = (int) (screamWidth / (3.0 / 4.0));
                markView.setMaskSize(screamWidth, targetHight, width, height);
            }
        });
//        int screamWidth = (int) (UiUtil.getScreamWidth(this) * 0.9);
//        int targetHight = (int) (screamWidth / (3.0 / 4.0));
//        markView.setMaskSize(screamWidth, targetHight, UiUtil.getScreamWidth(this), UiUtil.getScreamHeight(this));
        ensureCameraPermission();
        previewView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                FocusMeteringAction action = new FocusMeteringAction.Builder(
                        previewView.getMeteringPointFactory()
                                .createPoint(event.getX(), event.getY())).build();
                try {
                    showTapView((int) event.getX(), (int) event.getY());
                    Log.d("Camera", "Focus camera");
                    mCamera.getCameraControl().startFocusAndMetering(action);
                } catch (Exception e) {
                    Log.e("Camera", "Error focus camera");
                }
                return false;
            }
        });
    }

    private void showTapView(int x, int y) {
        Log.d("Camera", "Tap x:" + x + " y:" + y);
        PopupWindow popupWindow = new PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        // popupWindow.setBackgroundDrawable(getDrawable(android.R.color.holo_blue_bright));
        ImageView imageView = new ImageView(this);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(CameraUiUtil.dip2px(this, 40), CameraUiUtil.dip2px(this, 40)));
        imageView.setImageResource(R.mipmap.ic_launcher);
        popupWindow.setContentView(imageView);
        // popupWindow.showAtLocation(binding.previewView, Gravity.CENTER, x, y);
        popupWindow.showAsDropDown(previewView, x - CameraUiUtil.dip2px(this, 40), y - CameraUiUtil.dip2px(this, 40));
        previewView.postDelayed(popupWindow::dismiss, 300);
        previewView.playSoundEffect(SoundEffectConstants.CLICK);
    }

    //拍照
    public void onCaptureGo(View view) {
        ensureAudioStoragePermission(REQUEST_STORAGE);
    }

    //切换是否是拍照还是拍视频
    public void onChangeModeGo(View view) {
        isVideoMode = !isVideoMode;
        changeMode();
    }

    //切换是否是剪切
    public void onCurtModeGo(View view) {
         if(markView.getVisibility()==View.VISIBLE){
             markView.setVisibility(View.GONE);
         }else {
             markView.setVisibility(View.VISIBLE);
         }
    }

    //拍视频
    public void onVideoGo(View view) {
        if (!isRecording) {
            // Check permission first.
            ensureAudioStoragePermission(REQUEST_STORAGE_VIDEO);
        } else {
            // Update status right now.
            toggleRecordingStatus();
        }
    }

    //灯光
    public void onNight(View view) {
        if (isVideoMode) {

        } else {
            int flashMode = mImageCapture.getFlashMode();
            String mode = "";
            if (flashMode == ImageCapture.FLASH_MODE_ON) {
                mImageCapture.setFlashMode(ImageCapture.FLASH_MODE_AUTO);
                mode = "自动";
            } else if (flashMode == ImageCapture.FLASH_MODE_OFF) {
                mImageCapture.setFlashMode(ImageCapture.FLASH_MODE_ON);
                mode = "开";
            } else if (flashMode == ImageCapture.FLASH_MODE_AUTO) {
                mImageCapture.setFlashMode(ImageCapture.FLASH_MODE_OFF);
                mode = "关";
            }
            night.setText(mode);
        }
    }

    //解析二维码
    public void onAnalyzeGo(View view) {
        if (mImageAnalysis == null) {
            return;
        }
        capture.setVisibility(View.GONE);
        video.setVisibility(View.GONE);

        if (!isAnalyzing) {
            Log.d("Camera", "setAnalyzer()");
            mImageAnalysis.setAnalyzer(CameraXExecutors.mainThreadExecutor(), image -> {
                Log.d("Camera", "analyze() image:" + image);
                analyzeQRCode(image);
            });
        } else {
            Log.d("Camera", "clearAnalyzer()");
            mImageAnalysis.clearAnalyzer();
        }
        isAnalyzing = !isAnalyzing;
        qrCodeZone.setVisibility(isAnalyzing ? View.VISIBLE : View.GONE);
    }

    private void analyzeQRCode(@NonNull ImageProxy imageProxy) {
        ByteBuffer byteBuffer = imageProxy.getPlanes()[0].getBuffer();
        byte[] data = new byte[byteBuffer.remaining()];
        byteBuffer.get(data);

        int width = imageProxy.getWidth(), height = imageProxy.getHeight();
        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
                data, width, height, 0, 0, width, height, false);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

        Result result;
        try {
            result = multiFormatReader.decode(bitmap);
            Log.d("Camera", "result:" + result);
        } catch (Exception e) {
            Log.e("Camera", "Error decoding barcode");
            result = null;
        }
        showQRCodeResult(result);
        imageProxy.close();
    }

    private void showQRCodeResult(@Nullable Result result) {
        qrCodeResult.post(() ->
                qrCodeResult.setText(result != null ? "Link:\n" + result.getText() : ""));
        qrCodeResult.playSoundEffect(SoundEffectConstants.CLICK);
    }

    private void changeMode() {
        if (isVideoMode) {
            capture.setVisibility(View.GONE);
            video.setVisibility(View.VISIBLE);
        } else {
            capture.setVisibility(View.VISIBLE);
            video.setVisibility(View.GONE);
        }
        bindPreview(mCameraProvider, previewView, isVideoMode);
    }


    private void bindPreview(@NonNull ProcessCameraProvider cameraProvider,
                             PreviewView previewView, boolean isVideo) {
        Preview.Builder previewBuilder = new Preview.Builder();
        ImageCapture.Builder captureBuilder = new ImageCapture
                .Builder()
                .setTargetRotation(previewView.getDisplay().getRotation());
        CameraSelector cameraSelector = isBack ? CameraSelector.DEFAULT_BACK_CAMERA
                : CameraSelector.DEFAULT_FRONT_CAMERA;

        setPreviewExtender(previewBuilder, cameraSelector);
        mPreview = previewBuilder.build();

        cameraProvider.unbindAll();
        if (isVideo) {
            mVideoCapture = new VideoCapture.Builder()
                    .setTargetRotation(previewView.getDisplay().getRotation())
                    .setVideoFrameRate(25)
                    .setBitRate(3 * 1024 * 1024)
                    .build();

            mCamera = cameraProvider.bindToLifecycle(this, cameraSelector,
                    mPreview, mVideoCapture);
        } else {

            setCaptureExtender(captureBuilder, cameraSelector);
            mImageCapture = captureBuilder
                    .build();
//            mImageCapture .setFlashMode();
            mImageCapture.setTargetRotation(previewView.getDisplay().getRotation());
            //分子分母Rational int numerator, int denominator
//            mImageCapture.setCropAspectRatio(new Rational(1, 3));
            mImageCapture.setCropAspectRatio(new Rational(CameraUiUtil.getScreamWidth(this), CameraUiUtil.getScreamHeight(this)));
//            mImageCapture.setViewPortCropRect(new Rect(100,100,500,1000));

            //图像分析
            mImageAnalysis = new ImageAnalysis.Builder()
                    .setTargetRotation(previewView.getDisplay().getRotation())
                    .setTargetResolution(new Size(720, 1440))
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build();

            mCamera = cameraProvider.bindToLifecycle(this, cameraSelector,
                    mPreview, mImageCapture, mImageAnalysis);
        }
        mPreview.setSurfaceProvider(previewView.getSurfaceProvider());
    }

    /**
     * 权限
     *
     * @param requestId
     */
    private void ensureAudioStoragePermission(int requestId) {
        if (requestId == REQUEST_STORAGE) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                Log.d("Camera", "no storage permission & request");
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestId);
                return;
            }

            if (requestId == REQUEST_STORAGE) {
                //拍照
                takenPictureInternal(true);
            }
        } else if (requestId == REQUEST_STORAGE_VIDEO) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
                    != PackageManager.PERMISSION_GRANTED) {
                Log.d("Camera", "no storage or audio permission & request");
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                Manifest.permission.RECORD_AUDIO}, requestId);
                return;
            }
            recordVideo();
        }
    }


    @SuppressLint("RestrictedApi")
    private void takenPictureInternal(boolean isExternal) {
        Log.d("Camera", "takenPictureInternal isExternal:" + isExternal);


//        String path=this.getCacheDir().getAbsolutePath()+File.separator+System.currentTimeMillis()+".jpeg";
        String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() + File.separator + System.currentTimeMillis() + ".jpeg";

        new File(this.getCacheDir().getAbsolutePath() + File.separator).mkdirs();
        Log.d("Camera", "path:" + path);
//        ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(new File(path)).build();
        final ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, CAPTURED_FILE_NAME
                + "_" + picCount++);
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");

        ImageCapture.OutputFileOptions outputFileOptions =
                new ImageCapture.OutputFileOptions
                        .Builder(new File(path))
//                        .Builder( getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
                        .build();
        if (mImageCapture != null) {
            if(markView.getVisibility()==View.GONE){

                mImageCapture.takePicture(outputFileOptions, CameraXExecutors.mainThreadExecutor(),
                        new ImageCapture.OnImageSavedCallback() {
                            @Override
                            public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                                Log.d("Camera", "outputFileResults:"
                                        + outputFileResults.getSavedUri()
                                        + " picCount:" + picCount);
//                            Toast.makeText(CameraXActivity01.this, "Picture got"
//                                    + (outputFileResults.getSavedUri() != null
//                                    ? " @ " + outputFileResults.getSavedUri().getPath()
//                                    : "") + ".", Toast.LENGTH_SHORT)
//                                    .show();
                                Bitmap bitmap = BitmapFactory.decodeFile(path);
                                Toast.makeText(CameraXDemoActivity01.this, "图片高度：" + bitmap.getHeight() +  "图片宽度：" + bitmap.getWidth() + "图片大小：" + new File(path).length() / 1024, Toast.LENGTH_LONG).show();

                            }

                            @Override
                            public void onError(@NonNull ImageCaptureException exception) {
                                Log.d("Camera", "onError:" + exception.getImageCaptureError());
                            }
                        });
            } else {
                mImageCapture.takePicture(CameraXExecutors.mainThreadExecutor(),
                        new ImageCapture.OnImageCapturedCallback() {
                            @SuppressLint("UnsafeExperimentalUsageError")
                            @Override
                            public void onCaptureSuccess(@NonNull ImageProxy image) {
                                super.onCaptureSuccess(image);
                                ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
                                byte[] data = new byte[byteBuffer.remaining()];
                                byteBuffer.get(data);

                                int width = image.getWidth(), height = image.getHeight();
                                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                                if (width > height) {
                                    //竖屏旋转照片
                                    Matrix matrix = new Matrix();
                                    matrix.reset();
                                    if (isBack) {
//                                    matrix.postScale(-1, 1);
//                                    matrix.preRotate(270);
                                        matrix.preRotate(90);
                                    } else {
                                        matrix.postScale(-1, 1);
                                        matrix.preRotate(-90);
                                    }
                                    bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                                }
                                if (markView.maskWidth > 0 && markView.maskHeight > 0) {
                                    int w = bitmap.getWidth();
                                    int h = bitmap.getHeight();
                                    int targety= (int) (h*markView.maskHeight/(double)markView.height);
                                    int targetx= (int) (markView.maskWidth*targety/(double)markView.maskHeight);
                                    int y = (h - targety) / 2;
                                    int x = (w - targetx) / 2;
                                    bitmap = Bitmap.createBitmap(bitmap, x, y, targetx, targety);
                                }
                                result.setImageBitmap(bitmap);
                                result.setVisibility(View.VISIBLE);
                                String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() + File.separator + System.currentTimeMillis() + ".jpeg";
//                                savePicture(path, bitmap);
                                CameraFileUtils.savePictureByBitmap(path, bitmap);
                                image.close();

                            }

                            @Override
                            public void onError(@NonNull ImageCaptureException exception) {
                                Log.d("Camera", "onError:" + exception.getImageCaptureError());
                            }
                        });
            }
        }
    }

    @SuppressLint("RestrictedApi")
    private void recordVideo() {
        Log.d("Camera", "recordVideo() isCameraXHandling:" + isCameraXHandling);
        // Ensure recording is done before recording again cause stopRecording is async.
        if (isCameraXHandling) return;

        Log.d("Camera", "recordVideo()");
        final ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, RECORDED_FILE_NAME
                + "_" + recCount++);
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, RECORDED_FILE_NAME_END);

        Log.d("Camera", "recordVideo() startRecording");
        try {
            mVideoCapture.startRecording(
                    new VideoCapture.OutputFileOptions.Builder(getContentResolver(),
                            MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues)
                            .build(),
                    // CameraXExecutors.mainThreadExecutor(),
                    CameraXExecutors.ioExecutor(),
                    new VideoCapture.OnVideoSavedCallback() {
                        @Override
                        public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
                            Log.d("Camera", "onVideoSaved outputFileResults:"
                                    + outputFileResults.getSavedUri().getPath());
                            CameraXExecutors.mainThreadExecutor().execute(() -> Toast.makeText(CameraXDemoActivity01.this,
                                    "Video got" + (outputFileResults.getSavedUri() != null ?
                                            " @ " + outputFileResults.getSavedUri().getPath() : "")
                                            + ".", Toast.LENGTH_LONG).show());
//                            Toast.makeText(DemoActivityLite.this,
//                                    "Video got" + (outputFileResults.getSavedUri() != null ?
//                                            " @ " + outputFileResults.getSavedUri().getPath(): "")
//                                            + ".", Toast.LENGTH_LONG).show();
                            videoRecordingPrepared();
                        }

                        @Override
                        public void onError(int videoCaptureError, @NonNull String message,
                                            @Nullable Throwable cause) {
                            Log.d("Camera", "onError videoCaptureError:"
                                    + videoCaptureError + " message:" + message, cause);
                            videoRecordingPrepared();
                        }
                    }
            );
        } catch (Exception e) {
            Log.e("Camera", "Record video error:", e);
        }
        toggleRecordingStatus();
        isCameraXHandling = true;
    }

    // Enable record button after recording stopped.
    private void videoRecordingPrepared() {
        Log.d("Camera", "videoRecordingPrepared()");
        isCameraXHandling = false;
        // Keep disabled status for a while to avoid fast click error with "Muxer stop failed!".
        video.postDelayed(() -> video.setEnabled(true), 500);
    }

    @SuppressLint("RestrictedApi")
    private void toggleRecordingStatus() {
        Log.d("Camera", "toggleRecordingStatus() isVideoMode:" + isVideoMode + " isRecording:" + isRecording);
        if (!isVideoMode) return;

        isRecording = !isRecording;
        video.setText(isRecording
                ? "正在拍视频" : "拍视频");

        // Stop recording when toggle to false.
        if (!isRecording && mVideoCapture != null) {
            Log.d("Camera", "toggleRecordingStatus() stopRecording");
            mVideoCapture.stopRecording();
            // Keep record button disabled till video recording truly stopped.
            video.post(() -> video.setEnabled(false));
        }
    }

    private void ensureCameraPermission() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            Log.d("Camera", "no camera permission & request");
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);
            return;
        }
        setupCamera(previewView);
    }

    public void onChangeGo(View view) {
        if (mCameraProvider != null) {
            isBack = !isBack;
            bindPreview(mCameraProvider, previewView);
            if (mImageAnalysis != null) {
                mImageAnalysis.clearAnalyzer();
            }
        }
    }


    private void setupCamera(PreviewView previewView) {
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
                ProcessCameraProvider.getInstance(this);
        cameraProviderFuture.addListener(() -> {
            try {
                mCameraProvider = cameraProviderFuture.get();
                bindPreview(mCameraProvider, previewView);
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        }, ContextCompat.getMainExecutor(this));
    }


    private void bindPreview(@NonNull ProcessCameraProvider cameraProvider,
                             PreviewView previewView) {
        bindPreview(cameraProvider, previewView, false);
    }


    private void setPreviewExtender(Preview.Builder builder, CameraSelector cameraSelector) {
        BeautyPreviewExtender beautyPreviewExtender = BeautyPreviewExtender.create(builder);
        if (beautyPreviewExtender.isExtensionAvailable(cameraSelector)) {
            // Enable the extension if available.
            Log.d("Camera", "beauty preview extension enable");
            beautyPreviewExtender.enableExtension(cameraSelector);
        } else {
            Log.d("Camera", "beauty preview extension not available");
        }
    }

    private void setCaptureExtender(ImageCapture.Builder builder, CameraSelector cameraSelector) {
        NightImageCaptureExtender nightImageCaptureExtender = NightImageCaptureExtender.create(builder);
        if (nightImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
            // Enable the extension if available.
            Log.d("Camera", "night capture extension enable");
            nightImageCaptureExtender.enableExtension(cameraSelector);
        } else {
            Log.d("Camera", "night capture extension not available");
        }
        HdrImageCaptureExtender hdrImageCaptureExtender = HdrImageCaptureExtender.create(builder);

        if(hdrImageCaptureExtender.isExtensionAvailable(cameraSelector)){
            hdrImageCaptureExtender.enableExtension(cameraSelector);
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Log.d("Camera", "requestCode:" + requestCode
                + " permissions:" + Arrays.toString(permissions)
                + " grantResults:" + Arrays.toString(grantResults));
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return;
            }
        }

        switch (requestCode) {
            case REQUEST_CAMERA:
                setupCamera(previewView);
                break;
            case REQUEST_STORAGE:
                takenPictureInternal(true);
                break;
            case REQUEST_STORAGE_VIDEO:
                recordVideo();
                break;
//            case REQUEST_STORAGE_BINDING:
//            case REQUEST_STORAGE_VIDEO_BINDING:
//                toggleVideoMode();
//                break;
            default:
                break;
        }
    }
}